#define RAW_C
/*----------------------------------------------*
 * include files            	 ������ͷ�ļ�   *
 *----------------------------------------------*/
 #include <stdio.h>
 #include <stdlib.h>
#include <unistd.h> 
#include <sys/socket.h> 
#include <sys/types.h> 
#include <sys/ioctl.h> 
#include <sys/stat.h> 
#include <linux/if_packet.h>  
#include <errno.h>
#include <netdb.h> 
#include <linux/if_ether.h>

#include <libmscommon/mscommon.h>
#include <libmscommon/msnetwork.h>
#include <libmscommon/mstypes.h>
#include <libmscommon/msnetframe.h>
#include <libmscommon/msstring.h>
#include <libmslog/mslog.h>
#include "msprotocol.h"

#define FLAG "RAW"

#define NUM_FILTER	10
typedef struct RAWContext {
	struct sockaddr_ll  dstaddr; 
	struct sockaddr_in peeraddr;
	ms_byte filter_mac[18*NUM_FILTER];
	ms_byte filter_mac_source[18*NUM_FILTER];
	ms_byte filter_mac_dest[18*NUM_FILTER];
	ms_byte filter_protocol[16*NUM_FILTER];
	ms_byte filter_ip[16*NUM_FILTER];
	ms_byte filter_ip_source[16*NUM_FILTER];
	ms_byte filter_ip_dest[16*NUM_FILTER];
	ms_s32 filter_port;
	ms_s32 filter_port_source;
	ms_s32 filter_port_dest;
	MSFRAMEFILTERConfig msframefilter_config;
} RAWContext;

int raw_open(URLContext * s)
{
	if(1==s->is_connected){
		return 0;
	}
	RAWContext * praw_ctt=s->priv_data=(void *)ms_mallocDes(sizeof(RAWContext),"RAWContext",s->url);
	if(NULL==s->priv_data){
		ms_errRet(-1, "ms_malloc RAWContext faild(%d,%s)",errno,strerror(errno));
	}

	ms_verbose("===========open %s,and find options",s->url);	
	ms_byte *p = strchr(s->url, '?');
    if (p) {
		ms_byte buf[256]={0};
        if (msstr_api_findTag(buf, sizeof(buf), "filter_mac", p)) {
			ms_strcpy(praw_ctt->filter_mac, buf);
			praw_ctt->msframefilter_config.filter_mac=praw_ctt->filter_mac;
			ms_debug("find  filter_mac=%s",praw_ctt->filter_mac);
        }
        if (msstr_api_findTag(buf, sizeof(buf), "filter_mac_source", p)) {
			ms_strcpy(praw_ctt->filter_mac_source, buf);
			praw_ctt->msframefilter_config.filter_mac_source=praw_ctt->filter_mac_source;
			ms_debug("find  filter_mac_source=%s",praw_ctt->filter_mac_source);
        }	
        if (msstr_api_findTag(buf, sizeof(buf), "filter_mac_dest", p)) {
			ms_strcpy(praw_ctt->filter_mac_dest, buf);
			praw_ctt->msframefilter_config.filter_mac_dest=praw_ctt->filter_mac_dest;
			ms_debug("find  filter_mac_dest=%s",praw_ctt->filter_mac_dest);
        }	
		
        if (msstr_api_findTag(buf, sizeof(buf), "filter_protocol", p)) {
			ms_strcpy(praw_ctt->filter_protocol, buf);
			praw_ctt->msframefilter_config.filter_protocol=praw_ctt->filter_protocol;
			ms_debug("find  filter_protocol=%s",praw_ctt->filter_protocol);
        }
				
        if (msstr_api_findTag(buf, sizeof(buf), "filter_ip", p)) {
			ms_strcpy(praw_ctt->filter_ip, buf);
			praw_ctt->msframefilter_config.filter_ip=praw_ctt->filter_ip;
			ms_debug("find  filter_ip=%s",praw_ctt->filter_ip);
        }		
        if (msstr_api_findTag(buf, sizeof(buf), "filter_ip_source", p)) {
			ms_strcpy(praw_ctt->filter_ip_source, buf);
			praw_ctt->msframefilter_config.filter_ip_source=praw_ctt->filter_ip_source;
			ms_debug("find  filter_ip_source=%s",praw_ctt->filter_ip_source);
        }	
        if (msstr_api_findTag(buf, sizeof(buf), "filter_ip_dest", p)) {
			ms_strcpy(praw_ctt->filter_ip_dest, buf);
			praw_ctt->msframefilter_config.filter_ip_dest=praw_ctt->filter_ip_dest;
			ms_debug("find  filter_ip_dest=%s",praw_ctt->filter_ip_dest);
        }	

        if (msstr_api_findTag(buf, sizeof(buf), "filter_port", p)) {
			praw_ctt->filter_port=ms_atoi(buf);
			praw_ctt->msframefilter_config.filter_port=praw_ctt->filter_port;
			ms_debug("find  filter_port=%d",praw_ctt->filter_port);
        }
        if (msstr_api_findTag(buf, sizeof(buf), "filter_port_source", p)) {
			praw_ctt->filter_port_source=ms_atoi(buf);
			praw_ctt->msframefilter_config.filter_port_source=praw_ctt->filter_port_source;
			ms_debug("find  filter_port_source=%d",praw_ctt->filter_port_source);
        }
        if (msstr_api_findTag(buf, sizeof(buf), "filter_port_dest", p)) {
			praw_ctt->filter_port_dest=ms_atoi(buf);
			praw_ctt->msframefilter_config.filter_port_dest=praw_ctt->filter_port_dest;
			ms_debug("find  filter_port_dest=%d",praw_ctt->filter_port_dest);
        }	
	}
	
	s->fd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
	if(s->fd <0){
		ms_errGoto(fail,"create socket  failed(%d,%s)",errno,strerror(errno));
	}
	if( (s->flags&FLAG_WRITE)){
		if(ms_null!=s->ifcOut){
			struct ifreq if_index_out;  
			bzero(&if_index_out, sizeof(if_index_out));  
			strcpy(if_index_out.ifr_name, s->ifcOut);  
			if (ioctl(s->fd, SIOCGIFINDEX, &if_index_out) < 0) {  
				ms_errGoto(fail,"ioctl SIOCGIFINDEX(%s) failed(%d,%s)",s->ifcOut,errno,strerror(errno));
			}  
			//bind out interface
			ms_debug("set %s to IFF_PROMISC,and bind output",s->ifcOut);
			msnet_api_setIfaceFlags(s->fd, s->ifcOut, IFF_PROMISC);
			bzero(&praw_ctt->dstaddr, sizeof(praw_ctt->dstaddr));  
			praw_ctt->dstaddr.sll_ifindex = if_index_out.ifr_ifindex;  
			praw_ctt->dstaddr.sll_halen = ETH_ALEN;  	
			if(msnet_api_bindIface(s->fd,s->ifcOut)<0){
				ms_errGoto(fail, "msnet_api_bindIface failed %s(%d,%s) ", s->url, errno, strerror(errno));
			}
		}else{
			ms_waring("[%s]No set interfaceout",s->url);
		}
	}else{
		if(ms_null!=s->ifcIn){
			struct ifreq if_index_in;  
			bzero(&if_index_in, sizeof(if_index_in));  
			strcpy(if_index_in.ifr_name, s->ifcIn);  
			if (ioctl(s->fd, SIOCGIFINDEX, &if_index_in) < 0) {  
				ms_errGoto(fail,"ioctl SIOCGIFINDEX(%s) failed(%d,%s)",s->ifcIn,errno,strerror(errno));
			}
			//bind in interface
			struct sockaddr_ll  sll; 
			sll.sll_family = AF_PACKET;
			sll.sll_ifindex = if_index_in.ifr_ifindex;
			sll.sll_protocol = htons(ETH_P_ALL);
			if(bind(s->fd , (struct sockaddr *) &sll, sizeof(sll))<0){
				ms_errGoto(fail,"bind  failed(%d,%s)",errno,strerror(errno));
			}
			if(msnet_api_bindIface(s->fd,s->ifcIn)<0){
				ms_errGoto(fail, "msnet_api_bindIface failed %s(%d,%s) ", s->url, errno, strerror(errno));
			}
		}else{
			ms_waring("[%s]No set interfacein",s->url);
		}
	}
	s->is_connected=1;
	return 0;
fail:
	ms_deMalloc(praw_ctt);
	close(s->fd);
	s->is_connected=0;
	return -1;
}

int raw_read(URLContext * s,ms_u08 *buf,int len)
{
	RAWContext * praw_ctt=s->priv_data;
	int sockaddr_len = sizeof( struct sockaddr_in  );
//从网卡读取RAW原始数据	
	int recv_num = recvfrom( s->fd, (char *)buf, len, 0, ( struct sockaddr * )&praw_ctt->peeraddr, &sockaddr_len ); 
	if (recv_num < 0) {
		ms_error("recvfrom  failed(%d,%s)",errno,strerror(errno));
	} 
//对	RAW原始数据进行过滤，如果不符合规则，则直接丢掉
	if(ms_false==msframe_api_filterFrame(s->url,buf, &praw_ctt->msframefilter_config)){
		recv_num =0;
	}
	return recv_num;
}

int raw_write(URLContext * s,unsigned char *buf,int len)
{
	RAWContext * praw_ctt=s->priv_data;
	int total_len=0;
//对	RAW原始数据进行过滤，如果符合规则，才进行发送，否则直接丢掉
	if(ms_true==msframe_api_filterFrame(s->url,buf, &praw_ctt->msframefilter_config)){//drop
		total_len=sendto(s->fd, buf, len, 0, (struct sockaddr*)&praw_ctt->dstaddr, sizeof(praw_ctt->dstaddr));
		if ( total_len< 0) {
			ms_error("sendto(%d)  failed(%d,%s)",len,errno,strerror(errno));
		} 
	}
	return total_len;
}

int raw_close(URLContext * s)
{	
	if(0==s->is_connected){
		return 0;
	}
	RAWContext * praw_ctt=s->priv_data;
	ms_deMalloc(praw_ctt);
	close(s->fd);
	s->is_connected=0;
	return 0;
}
URLProtocol ffurl_raw_protocol={
	.nameDes	= msptc_getPtcNameDes(msptc_raw),
    .url_open	= raw_open,
    .url_read	= raw_read,
    .url_write	= raw_write,
    .url_close	= raw_close,
    .flags		=STREAM_LIVE,
    .next	=NULL,
};

#undef RAW_C
